#include "ModelDisplayer.h"

ModelDisplayer::ModelDisplayer(std::shared_ptr<IModelFileLoader> model_reader, std::shared_ptr<ViewCamera> view_camera)
{
    m_sptr_modelLoader = model_reader;
    m_sptr_camera = view_camera;
    m_p_program = new QOpenGLShaderProgram(this);
}

ModelDisplayer::~ModelDisplayer()
{
    if(m_p_program)
        delete m_p_program;
}

template<typename T>
QList<T> flattenDouble(const QList<QList<T>>& nestedList) {
    QList<T> result;

    // 预先分配空间
    int totalSize = 0;
    for (const auto& inner : nestedList) {
        totalSize += inner.size();
    }
    result.reserve(totalSize);

    // 展平
    for (const auto& inner : nestedList) {
        result.append(inner);
    }

    return result;
}

#include "ModelFormation.h"
#include <QDebug>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QFile>

// 辅助函数：从JSON字符串解析为Vertex数组
QVector<Vertex> parseJsonToVertices(const QString& jsonStr) {
    QVector<Vertex> vertices;

    // 1. 解析JSON文档（处理格式错误）
    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonStr.toUtf8());
    if (jsonDoc.isNull()) {
        qCritical() << "[JSON解析错误] 无效的JSON格式（可能是语法错误或编码问题）";
        return vertices;
    }

    // 2. 根节点必须是数组（匹配你的JSON结构：根为数组，内层嵌套顶点组）
    if (!jsonDoc.isArray()) {
        qCritical() << "[JSON结构错误] 根节点不是数组（预期嵌套数组结构）";
        return vertices;
    }
    QJsonArray rootArray = jsonDoc.array();

    // 3. 遍历根数组（外层数组：通常对应"层"或"分组"）
    for (int layerIdx = 0; layerIdx < rootArray.size(); layerIdx++) {
        QJsonValue layerVal = rootArray[layerIdx];
        if (!layerVal.isArray()) {
            qWarning() << "[JSON结构警告] 外层索引" << layerIdx << "不是数组，跳过该元素";
            continue;
        }
        QJsonArray layerArray = layerVal.toArray();

        // 4. 遍历层内数组（中层数组：通常对应"顶点组"）
        for (int groupIdx = 0; groupIdx < layerArray.size(); groupIdx++) {
            QJsonValue groupVal = layerArray[groupIdx];
            if (!groupVal.isArray()) {
                qWarning() << "[JSON结构警告] 层" << layerIdx << "的组" << groupIdx << "不是数组，跳过该元素";
                continue;
            }
            QJsonArray vertexArray = groupVal.toArray();

            // 5. 遍历顶点数组（内层数组：每个元素是单个顶点对象）
            for (int vertIdx = 0; vertIdx < vertexArray.size(); vertIdx++) {
                QJsonValue vertVal = vertexArray[vertIdx];
                if (!vertVal.isObject()) {
                    qWarning() << "[JSON结构警告] 层" << layerIdx << "组" << groupIdx << "的顶点" << vertIdx << "不是对象，跳过该元素";
                    continue;
                }
                QJsonObject vertObj = vertVal.toObject();

                // 6. 提取顶点的"position"（必须有3个数值：x/y/z）
                if (!vertObj.contains("position") || !vertObj["position"].isArray()) {
                    qWarning() << "[JSON字段缺失] 顶点" << vertIdx << "缺少有效position字段，跳过";
                    continue;
                }
                QJsonArray posArray = vertObj["position"].toArray();
                if (posArray.size() != 3) {
                    qWarning() << "[JSON字段错误] 顶点" << vertIdx << "的position长度不是3（需x/y/z），跳过";
                    continue;
                }

                // 7. 提取顶点的"color"（必须有4个数值：r/g/b/a）
                // if (!vertObj.contains("color") || !vertObj["color"].isArray()) {
                //     // qWarning() << "[JSON字段缺失] 顶点" << vertIdx << "缺少有效color字段，跳过";
                //     continue;
                // }
                // QJsonArray colorArray = vertObj["color"].toArray();
                // if (colorArray.size() != 4) {
                //     qWarning() << "[JSON字段错误] 顶点" << vertIdx << "的color长度不是4（需r/g/b/a），跳过";
                //     continue;
                // }

                // 8. 构造Vertex对象（映射JSON字段 + 初始化默认值）
                Vertex vertex;
                // 位置：JSON的position → QVector3D
                vertex.pos = QVector3D(
                    static_cast<float>(posArray[0].toDouble()),
                    static_cast<float>(posArray[1].toDouble()),
                    static_cast<float>(posArray[2].toDouble())
                    );
                // 颜色：JSON的color → QVector4D（保留原始Alpha值）
                // vertex.color = QVector4D(
                //     static_cast<float>(colorArray[0].toDouble()),
                //     static_cast<float>(colorArray[1].toDouble()),
                //     static_cast<float>(colorArray[2].toDouble()),
                //     static_cast<float>(colorArray[3].toDouble())
                //     );
                // 其他字段：JSON中未提供，设合理默认值（可根据需求修改）
                vertex.norm = QVector3D(0.0f, 0.0f, 1.0f);       // 默认法向量（沿Z轴正方向）
                vertex.texCoord = QVector2D(0.0f, 0.0f);          // 默认纹理坐标（可后续根据UV规则补充）
                vertex.tangent = QVector3D(1.0f, 0.0f, 0.0f);     // 默认切线（沿X轴正方向）
                vertex.bitangent = QVector3D(0.0f, 1.0f, 0.0f);   // 默认副切线（沿Y轴正方向）
                vertex.materialIndex = 0;                          // 默认使用第0个材质（需确保材质列表非空）

                // 9. 添加到顶点数组
                vertices.append(vertex);
            }
        }
    }

    // 解析完成：输出统计信息
    if (vertices.isEmpty()) {
        qWarning() << "[解析结果] 未成功解析到任何顶点（检查JSON结构或字段）";
    } else {
        qInfo() << "[解析结果] 成功解析" << vertices.size() << "个顶点";
        // 调试：输出第一个顶点的信息（验证正确性）
        qDebug() << "[示例顶点] 位置：" << vertices[0].pos << " 颜色：" << vertices[0].color;
    }

    return vertices;
}

// 便捷函数：从JSON文件读取并转换为Vertex数组
QVector<Vertex> loadVerticesFromJsonFile(const QString& jsonFilePath) {
    QFile jsonFile(jsonFilePath);
    if (!jsonFile.exists()) {
        qCritical() << "[文件错误] 文件不存在：" << jsonFilePath;
        return QVector<Vertex>();
    }

    if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qCritical() << "[文件错误] 无法打开JSON文件：" << jsonFilePath
                    << " 错误原因：" << jsonFile.errorString();
        return QVector<Vertex>();
    }

    // 检查文件是否为空
    if (jsonFile.size() == 0) {
        qCritical() << "[文件错误] 文件为空：" << jsonFilePath;
        jsonFile.close();
        return QVector<Vertex>();
    }

    // 2. 读取文件内容
    QString jsonStr = jsonFile.readAll();
    jsonFile.close();

    qDebug() << "文件大小：" << jsonStr.size() << "字符";
    qDebug() << "文件前100字符：" << jsonStr.left(100);

    // 3. 调用字符串解析函数
    return parseJsonToVertices(jsonStr);
}

QVector<QVector<QVector<QPointF>>> loadContoursFromJson(const QString& filename) {
    QVector<QVector<QVector<QPointF>>> result;

    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly)) {
        qWarning() << "无法打开文件:" << filename;
        return result;
    }

    QByteArray data = file.readAll();
    file.close();

    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull()) {
        qWarning() << "JSON解析失败";
        return result;
    }

    QJsonArray slicesArray = doc.array();
    result.resize(slicesArray.size());

    for (int sliceIdx = 0; sliceIdx < slicesArray.size(); ++sliceIdx) {
        QJsonArray contoursArray = slicesArray[sliceIdx].toArray();
        QVector<QVector<QPointF>> sliceContours;
        sliceContours.resize(contoursArray.size());

        for (int contourIdx = 0; contourIdx < contoursArray.size(); ++contourIdx) {
            QJsonArray pointsArray = contoursArray[contourIdx].toArray();
            QVector<QPointF> contourPoints;
            contourPoints.resize(pointsArray.size());

            for (int pointIdx = 0; pointIdx < pointsArray.size(); ++pointIdx) {
                QJsonObject pointObj = pointsArray[pointIdx].toObject();
                QJsonArray positionArray = pointObj["position"].toArray();

                if (positionArray.size() >= 2) {
                    double x = positionArray[0].toDouble();
                    double y = positionArray[1].toDouble();
                    contourPoints[pointIdx] = QPointF(x, y);
                }
            }

            sliceContours[contourIdx] = contourPoints;
        }

        result[sliceIdx] = sliceContours;
    }

    qDebug() << "成功加载" << result.size() << "个切片";
    return result;
}

// static auto vv = loadVerticesFromJsonFile("processed_contours3D.json");

void ModelDisplayer::initializeGL()
{
    initializeOpenGLFunctions();
    glEnable(GL_DEPTH_TEST);
    glClearColor(0.3f, 0.5f, 1.0f, 1.0f);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    // 编译和链接着色器
    if(!compileAndLinkShaders(m_p_program, ":/vertex_shaders/shaders_code/vs/vertex_shader.vs", ":/fragment_shaders/shaders_code/fs/fragment_shader.fs"))
    {
        qDebug() << "Failed to compile and link shaders.";
        return;
    }

    // 初始化摄像机
    m_sptr_camera->setPerspective(static_cast<float>(width()) / static_cast<float>(height()), global_near_plane, global_far_plane);

    // 锁定鼠标
    m_sptr_camera->setMouseLockedStatus(false);
    setMouseTracking(true); // 启用鼠标跟踪
    QCursor::setPos(mapToGlobal(QPoint(width() / 5, height() / 5))); // 将鼠标放在左上角避免初始移动时发生模型万向锁

    // 初始化灯光跟随
    // updateLightPos(LightMoveMode_em::AsCamera);

    // 初始化颜色信号量
    initColorMode();

    // 初始化材质纹理（加载+缓存+ID赋值）
    initMaterialTextures();

    // 获取点云信息
    obtainPointCloud();

    // 设置模型相关着色器数据指针
    setModelShaderProgramDataFormation();

    // 设置模型初始相位，选择不翻转
    calAndSetModelInitPhase(false);

    // 设置顶点数据到 GPU
    setModelVertexData2Shader(flattenDouble(m_modelVertices), flattenDouble(m_modelIndices));
    // setModelVertexData2Shader(vv, flattenDouble(m_modelIndices));

    // 获取光照信息
    obtainLighting();
    setupLighting();
}

void ModelDisplayer::paintGL()
{
    // 清除颜色和深度缓冲
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 设置主场景视口
    glViewport(0, 0, this->width(), this->height());

    // 绘制主场景
    m_vao.bind();
    m_p_program->bind();

    // 设置基本 MVP 矩阵
    m_p_program->setUniformValue("model", m_model);
    m_p_program->setUniformValue("view", m_sptr_camera->getViewMatrix());
    m_p_program->setUniformValue("projection", m_sptr_camera->getProjectionMatrix());

    // 设置法线矩阵
    QMatrix3x3 normModelMatrix = m_model.normalMatrix();
    m_p_program->setUniformValue("normModelMatrix", normModelMatrix);

    // 设置简易光追
    m_p_program->setUniformValue("viewPos", m_sptr_camera->getEye());

    // 加载材质并绘制
    for(const auto& verticesPerMaterial : m_modelVertices)
    {
        int i = &verticesPerMaterial - &m_modelVertices.front();
        int matIdx = verticesPerMaterial.front().materialIndex;
        loadMaterialFromIndex(matIdx);
        glDrawElements(m_cur_draw_type, m_modelIndices[i].size(), GL_UNSIGNED_INT, nullptr);
    }

    // glDrawArrays(GL_POINTS, 0, vv.size());

    m_p_program->release();
    m_vao.release();
}

void ModelDisplayer::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void ModelDisplayer::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && !m_isMouseKeyLocked)
    {
        m_isMousePressed = true; // 标记鼠标按下
        m_lastMousePos = event->pos(); // 记录当前鼠标位置
    }
}

void ModelDisplayer::mouseMoveEvent(QMouseEvent *event)
{
    static bool firstMouse = true;

    if (m_isMousePressed)
    {
        // 防抖动
        if (firstMouse)
        {
            m_lastMousePos = event->pos();
            firstMouse = false;
            return;
        }

        // 计算鼠标偏移量
        QPoint delta = event->pos() - m_lastMousePos;
        m_lastMousePos = event->pos();

        m_sptr_camera->surroundOriginByMouseInput(delta);

        // updateLightPos(LightMoveMode_em::AsCamera);

        // 触发重绘
        update();
    }
}

void ModelDisplayer::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && !m_isMouseKeyLocked)
        m_isMousePressed = false; // 标记鼠标释放
}

void ModelDisplayer::wheelEvent(QWheelEvent *event)
{
    if(m_isMouseWheelLocked)
        return;

    // 将滚轮事件传递给相机
    m_sptr_camera->wheelEvent(event);

    // 更新透视投影矩阵
    m_sptr_camera->setPerspective(static_cast<float>(width()) / static_cast<float>(height()), global_near_plane, global_far_plane);

    // 触发重绘
    update();
}

bool ModelDisplayer::loadShaderSource(const QString &filePath, QString &source)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qDebug() << "Failed to open shader file:" << filePath;
        return false;
    }

    QTextStream stream(&file);
    source = stream.readAll();
    file.close();
    return true;
}

bool ModelDisplayer::compileAndLinkShaders(QOpenGLShaderProgram *p_program, const QString &vs_file_path, const QString &fs_file_path)
{
    if(p_program == nullptr)
        return false;

    QString vertexSource, fragmentSource;

    // 加载顶点着色器代码
    if (!loadShaderSource(vs_file_path, vertexSource))
    {
        return false;
    }

    // 加载片段着色器代码
    if (!loadShaderSource(fs_file_path, fragmentSource))
    {
        return false;
    }

    // 编译顶点着色器
    if (!p_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource))
    {
        qDebug() << "Vertex shader compile error:" << p_program->log();
        return false;
    }

    // 编译片段着色器
    if (!p_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentSource))
    {
        qDebug() << "Fragment shader compile error:" << p_program->log();
        return false;
    }

    // 链接着色器程序
    if (!p_program->link())
    {
        qDebug() << "Shader program link error:" << p_program->log();
        return false;
    }

    return true;
}

void ModelDisplayer::setModelShaderProgramDataFormation()
{
    if(m_p_program == nullptr)
    {
        qDebug()<<"Shader promgram has not been initialized. Abort building shader program.";
        return;
    }
    m_vao.create();
    m_vao.bind();

    m_vbo.create();
    m_vbo.bind();

    m_ebo.create();
    m_ebo.bind();

    m_p_program->bind();
    m_p_program->enableAttributeArray(0);
    m_p_program->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, pos), 3, sizeof(Vertex));

    m_p_program->enableAttributeArray(1);
    m_p_program->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, norm), 3, sizeof(Vertex));

    m_p_program->enableAttributeArray(2);
    m_p_program->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, color), 4, sizeof(Vertex));

    m_p_program->enableAttributeArray(3);
    m_p_program->setAttributeBuffer(3, GL_FLOAT, offsetof(Vertex, texCoord), 2, sizeof(Vertex));

    m_p_program->enableAttributeArray(4);
    m_p_program->setAttributeBuffer(4, GL_FLOAT, offsetof(Vertex, tangent), 3, sizeof(Vertex));

    m_p_program->enableAttributeArray(5);
    m_p_program->setAttributeBuffer(5, GL_FLOAT, offsetof(Vertex, bitangent), 3, sizeof(Vertex));

    m_vao.release();
    m_vbo.release();
    m_ebo.release();
    m_p_program->release();
}

void ModelDisplayer::initFBO(int width, int height)
{
    // 创建 FBO 并绑定纹理
    glGenFramebuffers(1, &m_fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);

    // 创建纹理（用于存储渲染结果）
    glGenTextures(1, &m_fboTexture);
    glBindTexture(GL_TEXTURE_2D, m_fboTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glGenRenderbuffers(1, &m_rboDepth);
    glBindRenderbuffer(GL_RENDERBUFFER, m_rboDepth);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_rboDepth);

    // 将纹理附加到帧缓冲
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_fboTexture, 0);

    // 检查 FBO 是否完整
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        qWarning("FBO is incomplete!");
    }

    // 恢复默认帧缓冲区
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void ModelDisplayer::cleanupFBO()
{
    if (m_fbo) {
        glDeleteFramebuffers(1, &m_fbo);
        m_fbo = 0;
    }

    if (m_fboTexture) {
        glDeleteTextures(1, &m_fboTexture);
        m_fboTexture = 0;
    }

    if (m_rboDepth) {
        glDeleteRenderbuffers(1, &m_rboDepth);
        m_rboDepth = 0;
    }
}

void ModelDisplayer::setModelVertexData2Shader(const QVector<Vertex> &model_vertices, const QVector<unsigned int> &model_indices)
{
    // 设置顶点数据
    m_vbo.bind();
    assert(model_vertices.size() * sizeof(Vertex) <= UINT_MAX);
    m_vbo.allocate(model_vertices.constData(), model_vertices.size() * sizeof(Vertex));

    // 设置索引数据
    m_ebo.bind();
    assert(model_indices.size() * sizeof(unsigned int) <= UINT_MAX);
    m_ebo.allocate(model_indices.constData(), model_indices.size() * sizeof(unsigned int));

    m_vbo.release();
    m_ebo.release();
}

GLuint ModelDisplayer::loadTextureWithCache(const QString &filePath, const QByteArray &embeddedData)
{
    // 检查缓存
    if (m_textureCache.contains(filePath))
    {
        return m_textureCache[filePath];
    }

    GLuint texID = 0;

    // 处理嵌入式纹理
    if (filePath.startsWith("*embedded_"))
    {
        int texIndex = filePath.mid(10).toInt();
        QImage texImage = loadEmbeddedTexture(embeddedData);
        if(!texImage.isNull())
        {
            texImage = texImage.convertToFormat(QImage::Format_RGBA8888);
            texID = createGLTexture(texImage);
        }
    }
    else
    {
        QImage texImage = loadExternalTexture(filePath);
        if (!texImage.isNull())
        {
            texImage = texImage.convertToFormat(QImage::Format_RGBA8888);
            texID = createGLTexture(texImage);
        }
    }

    if (texID != 0)
    {
        m_textureCache.insert(filePath, texID);
    }

    return texID;
}

GLuint ModelDisplayer::loadTextureWithCache(const QString &filePath, const QByteArray &embeddedData, QImage &out_texture_cpu)
{
    // 检查缓存
    if (m_textureCache.contains(filePath))
    {
        return m_textureCache[filePath];
    }

    GLuint texID = 0;

    // 处理嵌入式纹理
    if (filePath.startsWith("*embedded_"))
    {
        int texIndex = filePath.mid(10).toInt();
        QImage texImage = loadEmbeddedTexture(embeddedData);
        if(!texImage.isNull())
        {
            texID = createGLTexture(texImage);
            out_texture_cpu = texImage.convertToFormat(QImage::Format_RGBA8888);
        }
    }
    else
    {
        QImage texImage = loadExternalTexture(filePath);
        if (!texImage.isNull())
        {
            texImage = texImage.convertToFormat(QImage::Format_RGBA8888);
            texID = createGLTexture(texImage);
            out_texture_cpu = texImage;
        }
    }

    if (texID != 0)
    {
        m_textureCache.insert(filePath, texID);
    }

    return texID;
}

QImage ModelDisplayer::loadEmbeddedTexture(const QByteArray &textureData)
{
    if (textureData.isEmpty())
        return QImage();

    // 从内存加载图像
    QImage image;
    if (image.loadFromData(reinterpret_cast<const uchar*>(textureData.constData()), textureData.size()))
    {
        image = image.convertToFormat(QImage::Format_RGBA8888);
        return image;
    }
    else
    {
        qWarning() << "Failed to load embedded texture from memory data";
        return QImage();
    }
}

QImage ModelDisplayer::loadExternalTexture(const QString &filePath)
{
    if (filePath.isEmpty())
        return QImage();

    // 从磁盘加载图像
    QString fullPath;
    if (QFileInfo(filePath).isAbsolute())
        fullPath = filePath;
    else
        fullPath = m_sptr_modelLoader->getFullTexturePath(filePath);

    return QImage(fullPath).convertToFormat(QImage::Format_RGBA8888);
}

GLuint ModelDisplayer::createGLTexture(const QImage &image)
{
    GLuint texID;
    glGenTextures(1, &texID);
    glBindTexture(GL_TEXTURE_2D, texID);

    glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RGBA,
        image.width(), image.height(), 0,
        GL_RGBA, GL_UNSIGNED_BYTE, image.bits()
        );

    glGenerateMipmap(GL_TEXTURE_2D);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    return texID;
}

// void ModelDisplayer::initMaterialTextures()
// {
//     m_modelMaterials = m_sptr_modelLoader->getMaterials();

//     for (int i = 0; i < m_modelMaterials.size(); ++i)
//     {
//         Material& mat = m_modelMaterials[i];

//         QImage cpu_tex_diff, cpu_tex_spec, cpu_tex_norm;

//         // 处理漫反射纹理
//         if (!mat.diffuseTexturePath.isEmpty() || !mat.embeddedDiffuseTexture.isEmpty()) {
//             mat.diffuseTextureID = loadTextureWithCache(mat.diffuseTexturePath, mat.embeddedDiffuseTexture, cpu_tex_diff);
//         }

//         qDebug() << "Formation of cpu_tex_diff: " << cpu_tex_diff.format();

//         QString fileName = QString("cpu_tex_diff_%1.png").arg(i);
//         if (cpu_tex_diff.save(fileName)) {
//             qDebug() << "成功保存纹理图片：" << fileName;
//         } else if(cpu_tex_diff.isNull()){
//             qDebug() << "保存纹理图片失败：" << fileName
//                      << "，可能原因：图片为空";
//         } else {
//             qDebug() << "保存纹理图片失败：" << fileName
//                      << "，可能原因：图片格式不支持";
//         }

//         // 处理镜面纹理
//         if (!mat.specularTexturePath.isEmpty() || !mat.embeddedSpecularTexture.isEmpty()) {
//             mat.specularTextureID = loadTextureWithCache(mat.specularTexturePath, mat.embeddedSpecularTexture, cpu_tex_spec);
//         }

//         fileName = QString("cpu_tex_spec_%1.png").arg(i);
//         if (cpu_tex_spec.save(fileName)) {
//             qDebug() << "成功保存纹理图片：" << fileName;
//         } else if(cpu_tex_spec.isNull()){
//             qDebug() << "保存纹理图片失败：" << fileName
//                      << "，可能原因：图片为空";
//         } else {
//             qDebug() << "保存纹理图片失败：" << fileName
//                      << "，可能原因：图片格式不支持";
//         }

//         // 处理法线纹理
//         if (!mat.normalTexturePath.isEmpty() || !mat.embeddedNormalTexture.isEmpty()) {
//             mat.normalTextureID = loadTextureWithCache(mat.normalTexturePath, mat.embeddedNormalTexture, cpu_tex_norm);
//         }

//         fileName = QString("cpu_tex_norm_%1.png").arg(i);
//         if (cpu_tex_norm.save(fileName)) {
//             qDebug() << "成功保存纹理图片：" << fileName;
//         } else if(cpu_tex_norm.isNull()){
//             qDebug() << "保存纹理图片失败：" << fileName
//                      << "，可能原因：图片为空";
//         } else {
//             qDebug() << "保存纹理图片失败：" << fileName
//                      << "，可能原因：图片格式不支持";
//         }
//     }
// }

void ModelDisplayer::initMaterialTextures()
{
    m_modelMaterials = m_sptr_modelLoader->getMaterials();

    for (int i = 0; i < m_modelMaterials.size(); ++i)
    {
        Material& mat = m_modelMaterials[i];

        // 处理漫反射纹理
        if (!mat.diffuseTexturePath.isEmpty() || !mat.embeddedDiffuseTexture.isEmpty()) {
            mat.diffuseTextureID = loadTextureWithCache(mat.diffuseTexturePath, mat.embeddedDiffuseTexture);
        }

        // 处理镜面纹理
        if (!mat.specularTexturePath.isEmpty() || !mat.embeddedSpecularTexture.isEmpty()) {
            mat.specularTextureID = loadTextureWithCache(mat.specularTexturePath, mat.embeddedSpecularTexture);
        }

        // 处理法线纹理
        if (!mat.normalTexturePath.isEmpty() || !mat.embeddedNormalTexture.isEmpty()) {
            mat.normalTextureID = loadTextureWithCache(mat.normalTexturePath, mat.embeddedNormalTexture);
        }
    }
}

/**
 * @brief 将模型顶点投影到以质心为主轴、指定半径为radius的圆柱面上
 * @param vertices 原始顶点数据
 * @param centroid 质心坐标
 * @param radius 球面半径
 * @param isNormalize 是否保持顶点法向量（如果存在）
 */
inline void projectModelToCylinder(
    QVector<QVector<Vertex>>& vertices,
    const QVector3D& centroid,
    const QVector3D& planeNorm,
    float radius,
    bool isNormalize)
{
    for (auto& verticesPerMat : vertices) {
        for(auto& projectedVertex : verticesPerMat) {
            // 计算顶点相对于质心的向量
            QVector3D relativePos = projectedVertex.pos - QVector3D(centroid.x(), projectedVertex.pos.y(), centroid.z());
            if (relativePos.length() > 0.0f && projectedVertex.norm != QVector3D(0, 0, 0)) {
                // 将顶点投影到球面上
                float t = qAbs(QVector3D::dotProduct(projectedVertex.norm.normalized(), planeNorm.normalized()));
                float gt = QVector4D::dotProduct(projectedVertex.color, {0.299f, 0.587f, 0.114f, 0.0f})/* * std::max(projectedVertex.color.x(), std::max(projectedVertex.color.y(), projectedVertex.color.z()))*/;
                QVector3D projectedPos = projectedVertex.pos + relativePos.normalized() * (exp(t + gt) - 1) * radius;
                projectedVertex.pos = projectedPos;

                if (isNormalize) {
                    // 更新法向量为球面法向量（从球心指向顶点）
                    projectedVertex.norm = relativePos.normalized();
                }
            }
        }
    }
}

void ModelDisplayer::calAndSetModelInitPhase(bool isFlip)
{
    // 计算与设置STL模型初始相位
    m_centroid = ModelAttributesCalculator::calModelCentroid(m_sptr_modelLoader->getTriangles());
    m_model.translate(-m_centroid.x(), -m_centroid.y(), -m_centroid.z());
    // projectModelToCylinder(m_modelVertices, m_centroid, {1, 0, 0}, 0.01f, false);
    // m_model.scale(20.0f);
}

void ModelDisplayer::updateLightPos(LightMoveMode_em light_mode)
{
    // switch(light_mode)
    // {
    // case LightMoveMode_em::AsCamera:
    //     m_lightPos = m_camera.getEye();
    //     break;
    // case LightMoveMode_em::Fixed:
    //     break;
    // case LightMoveMode_em::Random:
    //     break;
    // case LightMoveMode_em::Period:
    //     break;
    // }
}

void ModelDisplayer::initColorMode()
{
    m_p_program->bind();
    m_p_program->setUniformValue("grayValueMode", m_isGrayScaleMode);
    m_p_program->release();
}

void ModelDisplayer::obtainPointCloud()
{
    m_modelVertices = m_sptr_modelLoader->getVertices();
    m_modelIndices = m_sptr_modelLoader->getVerticesIndices();
    qDebug() << "Loaded" << flattenDouble(m_modelVertices).size() << "vertices from model";
}

void ModelDisplayer::obtainLighting()
{
    m_lights = m_sptr_modelLoader->getLights();
    qDebug() << "Loaded" << m_lights.size() << "lights from model";
}

void ModelDisplayer::setupLighting()
{
    m_p_program->bind();
    m_p_program->setUniformValue("lightCount", (int)m_lights.size()); // 实际光源数量
    for (int i = 0; i < m_lights.size() && i < MAX_LIGHTS; ++i)
    {
        const auto& light = m_lights[i];
        QString baseName = QString("lights[%1]").arg(i);

        // 光源类型（0:方向光, 1:点光, 2:聚光灯）
        m_p_program->setUniformValue((baseName + ".type").toUtf8(), light.type);
        // 光源颜色
        m_p_program->setUniformValue((baseName + ".color").toUtf8(), light.color);
        // 位置和方向
        m_p_program->setUniformValue((baseName + ".position").toUtf8(), light.position);
        m_p_program->setUniformValue((baseName + ".direction").toUtf8(), light.direction);
        // 衰减参数
        m_p_program->setUniformValue((baseName + ".constant").toUtf8(), light.constant);
        m_p_program->setUniformValue((baseName + ".linear").toUtf8(), light.linear);
        m_p_program->setUniformValue((baseName + ".quadratic").toUtf8(), light.quadratic);
        // 聚光灯参数（注意：着色器中用弧度，而processLights中转为了角度，这里需要转回弧度）
        m_p_program->setUniformValue((baseName + ".cutOff").toUtf8(), qCos(qDegreesToRadians(light.cutOff)));
        m_p_program->setUniformValue((baseName + ".outerCutOff").toUtf8(), qCos(qDegreesToRadians(light.outerCutOff)));
    }
    m_p_program->release();
}

void ModelDisplayer::applyRadialGrayscaleValues(GrayScaleRange_em gray_scale_range)
{
    m_isGrayScaleMode = GL_TRUE;
    m_isPureColorMode = GL_FALSE;
    m_p_program->bind();
    m_p_program->setUniformValue("grayValueMode", m_isGrayScaleMode);
    m_p_program->release();

    float gray_value_scale;
    switch(gray_scale_range)
    {
    case GrayScaleRange_em::U8:
        gray_value_scale = 255.0f;
        break;
    case GrayScaleRange_em::U16:
        gray_value_scale = 65535.0f;
        break;
    }
    auto modelVertices = flattenDouble(m_modelVertices);
    // TODO(mengjinlang): 这里MSVC的并行库不能用const的数组，只能两段取点了
    QVector3D plane_norm = m_sptr_camera->getEye();
    QVector<float> projections;
    projections.reserve(modelVertices.size());
    for (const Vertex& v : modelVertices)
        projections.append(QVector3D::dotProduct(v.pos, plane_norm));

    auto [minIt, maxIt] = std::minmax_element(projections.begin(), projections.end());
    float minProj = *minIt;
    float maxProj = *maxIt;
    float range = maxProj - minProj;

    std::for_each(std::execution::par,
                  modelVertices.begin(),
                  modelVertices.end(),
                  [&](Vertex& vertex) {
                      std::size_t i = &vertex - &modelVertices[0];
                      float normalized = (projections[i] - minProj) / range;
                      float grayValue = (normalized * gray_value_scale) / gray_value_scale;
                      vertex.color = QVector4D(grayValue, grayValue, grayValue, 1.0f);
                      i++;
                  });
    setModelVertexData2Shader(modelVertices, flattenDouble(m_modelIndices));
    update();
}

void ModelDisplayer::applyGlobalGrayscaleValues(GrayScaleRange_em gray_scale_range)
{
    m_isGrayScaleMode = GL_TRUE;
    m_isPureColorMode = GL_FALSE;
    m_p_program->bind();
    m_p_program->setUniformValue("grayValueMode", m_isGrayScaleMode);
    m_p_program->setUniformValue("pureColorMode", m_isPureColorMode);
    m_p_program->release();

    float gray_value_scale;
    switch(gray_scale_range)
    {
    case GrayScaleRange_em::U8:
        gray_value_scale = 255.0f;
        break;
    case GrayScaleRange_em::U16:
        gray_value_scale = 65535.0f;
        break;
    }
    auto modelVertices = flattenDouble(m_modelVertices);

    // 计算所有顶点的亮度范围
    QVector<float> brightnessValues;
    brightnessValues.reserve(modelVertices.size());
    for (const Vertex& v : modelVertices) {
        float brightness = 0.299f * v.color.x() + 0.587f * v.color.y() + 0.114f * v.color.z();
        brightnessValues.append(brightness);
    }

    auto [minIt, maxIt] = std::minmax_element(brightnessValues.begin(), brightnessValues.end());
    float minBrightness = *minIt;
    float maxBrightness = *maxIt;
    float range = maxBrightness - minBrightness;

    std::for_each(std::execution::par, modelVertices.begin(), modelVertices.end(),
                  [&](Vertex& vertex) {
                      float brightness = 0.299f * vertex.color.x() + 0.587f * vertex.color.y() + 0.114f * vertex.color.z();
                      float normalized = (brightness - minBrightness) / range;
                      float grayValue = qBound(0.0f, normalized, 1.0f);

                      vertex.color = QVector4D(grayValue, grayValue, grayValue, vertex.color.w());
                  });
    setModelVertexData2Shader(modelVertices, flattenDouble(m_modelIndices));
    update();
}

void ModelDisplayer::cancelGrayscaleConvertion()
{
    m_isGrayScaleMode = GL_FALSE;
    m_p_program->bind();
    m_p_program->setUniformValue("grayValueMode", m_isGrayScaleMode);
    m_p_program->release();
    setModelVertexData2Shader(flattenDouble(m_modelVertices), flattenDouble(m_modelIndices));
    update();
}

void ModelDisplayer::cancelPureColorConvertion()
{
    m_isPureColorMode = GL_FALSE;
    m_p_program->bind();
    m_p_program->setUniformValue("pureColorMode", m_isPureColorMode);
    m_p_program->release();
    setModelVertexData2Shader(flattenDouble(m_modelVertices), flattenDouble(m_modelIndices));
    update();
}

void ModelDisplayer::setModelViewPortMatched()
{
    auto M = m_model;
    auto V = m_sptr_camera->getViewMatrix();
    auto modelVertices = flattenDouble(m_modelVertices);
    const float n = m_sptr_camera->getNearPlaneDistance();
    std::vector<float> x_proj(modelVertices.size());
    std::vector<float> y_proj(modelVertices.size());
    std::transform(std::execution::par,
                   modelVertices.begin(), modelVertices.end(),
                   x_proj.begin(),
                   [&](const Vertex& v) {
                       auto vec_in_view = V * M * QVector4D(v.pos, 1.0f);
                       float z = -vec_in_view.z();
                       return vec_in_view.x() * n / z;
                   });
    std::transform(std::execution::par,
                   modelVertices.begin(), modelVertices.end(),
                   y_proj.begin(),
                   [&](const Vertex& v) {
                       auto vec_in_view = V * M * QVector4D(v.pos, 1.0f);
                       float z = -vec_in_view.z();
                       return vec_in_view.y() * n / z;
                   });
    auto [left, right] = std::minmax_element(std::execution::par, x_proj.begin(), x_proj.end());
    auto [bottom, top] = std::minmax_element(std::execution::par, y_proj.begin(), y_proj.end());
    m_sptr_camera->setPerspective(*left, *right, *bottom, *top);
    update();
}

void ModelDisplayer::setModelViewPortFilled(int win_width, int win_height, ProjectionType projection_type)
{
    if (m_modelVertices.empty())
        return;
    auto M = m_model;
    auto V = m_sptr_camera->getViewMatrix();
    auto modelVertices = flattenDouble(m_modelVertices);
    double aspect_ratio = static_cast<double>(win_width) / win_height;
    const float n = m_sptr_camera->getNearPlaneDistance();
    std::vector<float> x_proj(modelVertices.size());
    std::vector<float> y_proj(modelVertices.size());
    auto getCoords = (projection_type == ProjectionType::Perspective)
                         ? getProjectionCoords<ProjectionType::Perspective>
                         : getProjectionCoords<ProjectionType::Orthogonal>;
    std::transform(std::execution::par,
                   modelVertices.begin(), modelVertices.end(),
                   x_proj.begin(),
                   [&](const Vertex& v) {
                       return getCoords(V, M, v, n).first;
                   });
    std::transform(std::execution::par,
                   modelVertices.begin(), modelVertices.end(),
                   y_proj.begin(),
                   [&](const Vertex& v) {
                       return getCoords(V, M, v, n).second;
                   });
    auto [left_iter, right_iter] = std::minmax_element(std::execution::par, x_proj.begin(), x_proj.end());
    auto [bottom_iter, top_iter] = std::minmax_element(std::execution::par, y_proj.begin(), y_proj.end());
    float left = *left_iter;
    float right = *right_iter;
    float bottom = *bottom_iter;
    float top = *top_iter;
    switch(projection_type)
    {
    case ProjectionType::Perspective:
    {
        float max_x_offset = std::max(std::fabs(left), std::fabs(right));
        float max_y_offset = std::max(std::fabs(bottom), std::fabs(top));
        if (max_x_offset < 1e-6f || max_y_offset < 1e-6f)
            return;
        float filled_fov;
        float required_fov_x = 2.0f * std::atan(max_x_offset / (n * static_cast<float>(aspect_ratio)));
        float required_fov_y = 2.0f * std::atan(max_y_offset / n);
        filled_fov = std::max(required_fov_x, required_fov_y);
        m_sptr_camera->setFOV(qRadiansToDegrees(filled_fov));
        m_sptr_camera->setPerspective(aspect_ratio, global_near_plane, global_far_plane);
    }
    break;
    case ProjectionType::Orthogonal:
    {
        // 计算当前模型范围的中心点和半宽高
        float center_x = (left + right) * 0.5f;
        float center_y = (bottom + top) * 0.5f;
        float half_width = (right - left) * 0.5f;
        float half_height = (top - bottom) * 0.5f;

        // 根据窗口宽高比调整范围
        if (half_width / half_height > aspect_ratio) {
            // 以宽度为准，等比缩放高度
            half_height = half_width / aspect_ratio;
        } else {
            // 以高度为准，等比缩放宽度
            half_width = half_height * aspect_ratio;
        }

        // 重新计算边界
        left = center_x - half_width;
        right = center_x + half_width;
        bottom = center_y - half_height;
        top = center_y + half_height;

        m_sptr_camera->setOrthogonal(left, right, bottom, top, n, 100.0f);
    }
    break;
    }
    update();
}

bool ModelDisplayer::saveFramebufferToImage(const QString &filePath, const QString& imageFormation, int image_width, int image_height)
{
    makeCurrent();

    m_vao.bind();
    m_p_program->bind();

    //初始化离屏渲染
    initFBO(image_width, image_height);

    // 绑定 FBO 并渲染
    glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);

    glEnable(GL_DEPTH_TEST);
    glClearColor(0.3f, 0.5f, 1.0f, 1.0f);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glViewport(0, 0, image_width, image_height);

    auto reserved_points = m_modelVertices;
    float reserved_fov = m_sptr_camera->getFOV();

    // 设置视窗填充
    setModelViewPortFilled(image_width, image_height, ProjectionType::Orthogonal);

    // 设置基本 MVP 矩阵
    m_p_program->setUniformValue("model", m_model);
    m_p_program->setUniformValue("view", m_sptr_camera->getViewMatrix());
    m_p_program->setUniformValue("projection", m_sptr_camera->getProjectionMatrix());

    // 设置法线矩阵
    QMatrix3x3 normModelMatrix = m_model.normalMatrix();
    m_p_program->setUniformValue("normModelMatrix", normModelMatrix);

    // 设置简易光追
    m_p_program->setUniformValue("viewPos", m_sptr_camera->getEye());

    // 加载材质并绘制
    for(const auto& verticesPerMaterial : m_modelVertices)
    {
        int i = &verticesPerMaterial - &m_modelVertices.front();
        int matIdx = verticesPerMaterial.front().materialIndex;
        loadMaterialFromIndex(matIdx);
        glDrawElements(GL_TRIANGLES, m_modelIndices[i].size(), GL_UNSIGNED_INT, nullptr);
    }

    // 读取像素
    QImage image(image_width, image_height, QImage::Format_RGBA8888);
    glReadPixels(0, 0, image_width, image_height, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());

    // 恢复视图
    m_modelVertices = reserved_points;
    m_sptr_camera->setFOV(reserved_fov);
    m_sptr_camera->setPerspective(static_cast<float>(width()) / static_cast<float>(height()), global_near_plane, global_far_plane);

    m_p_program->release();
    m_vao.release();

    // 恢复默认帧缓冲区
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    cleanupFBO();
    doneCurrent();

    // 保存图像
    return image.mirrored(false, true).save(filePath, imageFormation.toStdString().c_str());
}

void ModelDisplayer::resizeModel(float scale_factor)
{
    m_model.scale(scale_factor);
    update();
}

void ModelDisplayer::setPureColor(const QVector3D &pure_color)
{
    m_isPureColorMode = GL_TRUE;
    m_isGrayScaleMode = GL_FALSE;
    m_p_program->bind();
    m_p_program->setUniformValue("grayValueMode", m_isGrayScaleMode);
    m_p_program->setUniformValue("pureColorMode", m_isPureColorMode);
    m_p_program->release();

    auto modelVertices = flattenDouble(m_modelVertices);

    std::for_each(std::execution::par, modelVertices.begin(), modelVertices.end(),
                  [&](Vertex& vertex) {
                      vertex.color = QVector4D(pure_color.x(), pure_color.y(), pure_color.z(), 1.0f);
                  });
    setModelVertexData2Shader(modelVertices, flattenDouble(m_modelIndices));
    update();
}

void ModelDisplayer::showProcessedPointCloud(const QVector<QVector<Vertex>>& pointCloud)
{
    m_modelVertices = pointCloud;
    m_modelIndices.clear();
    m_cur_draw_type = DrawType_em::PointCloud;
    // 为每个材质组生成连续的点索引
    for (const QVector<Vertex>& vertices : pointCloud)
    {
        QVector<unsigned int> indices;
        indices.reserve(vertices.size());

        // 生成 0, 1, 2, 3, ... 的连续索引
        for (unsigned int i = 0; i < static_cast<unsigned int>(vertices.size()); ++i) {
            indices.append(i);
        }

        m_modelIndices.append(indices);
    }
    setModelVertexData2Shader(flattenDouble(m_modelVertices), flattenDouble(m_modelIndices));
    update();
}

void ModelDisplayer::loadMaterialFromIndex(int matIdx)
{
    // 输出点云时不具有材质
    if(matIdx < 0 || matIdx >= m_modelMaterials.size())
    {
        // 1. 禁用纹理
        m_p_program->setUniformValue("material.useDiffuseTex", GL_FALSE);
        m_p_program->setUniformValue("material.useSpecularTex", GL_FALSE);
        m_p_program->setUniformValue("material.useNormalTex", GL_FALSE);

        // 2. 材质参数设为纯黑，让光照计算的 ambient/diffuse/specular 都为 0
        m_p_program->setUniformValue("material.ambient", QVector3D(0.0f, 0.0f, 0.0f));   // 环境光贡献归零
        m_p_program->setUniformValue("material.diffuse", QVector3D(0.0f, 0.0f, 0.0f));   // 漫反射贡献归零
        m_p_program->setUniformValue("material.specular", QVector3D(0.0f, 0.0f, 0.0f));  // 镜面反射贡献归零
        m_p_program->setUniformValue("material.shininess", 0.0f);                         // 镜面反射强度归零

        // 3. 禁用额外颜色模式，避免干扰
        // m_p_program->setUniformValue("grayValueMode", GL_FALSE);
        // m_p_program->setUniformValue("pureColorMode", GL_FALSE);

        // 4. 光源数量设为 0，强制走默认光照逻辑（已被材质参数归零）
        m_p_program->setUniformValue("lightCount", 0);

        return;
    }
    const Material& mat = m_modelMaterials[matIdx];

    // 传递当前材质的基础参数
    m_p_program->setUniformValue("material.ambient", mat.ambient);
    m_p_program->setUniformValue("material.diffuse", mat.diffuse);
    m_p_program->setUniformValue("material.specular", mat.specular);
    m_p_program->setUniformValue("material.shininess", mat.shininess);

    // 绑定漫反射纹理（GL_TEXTURE0）
    bool hasDiffuseTex = (mat.diffuseTextureID != 0);
    m_p_program->setUniformValue("material.useDiffuseTex", hasDiffuseTex);
    if (hasDiffuseTex)
    {
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, mat.diffuseTextureID);
        m_p_program->setUniformValue("diffuseSampler", 0);
    }

    // 绑定镜面纹理（GL_TEXTURE1）
    bool hasSpecularTex = (mat.specularTextureID != 0);
    m_p_program->setUniformValue("material.useSpecularTex", hasSpecularTex);
    if (hasSpecularTex)
    {
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, mat.specularTextureID);
        m_p_program->setUniformValue("specularSampler", 1);
    }

    // 绑定法线纹理（GL_TEXTURE2）
    bool hasNormalTex = (mat.normalTextureID != 0);
    m_p_program->setUniformValue("material.useNormalTex", hasNormalTex);
    if (hasNormalTex)
    {
        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, mat.normalTextureID);
        m_p_program->setUniformValue("normalSampler", 2);
    }
}
